"""
钉钉 Stream Mode 机器人 - 接收用户消息
"""

import logging
import asyncio
import threading
from odoo import models, fields, api, _
from odoo.exceptions import ValidationError

_logger = logging.getLogger(__name__)

# 全局变量存储 Stream 客户端
_stream_client = None
_stream_thread = None

# 尝试导入 dingtalk_stream（如果未安装会在运行时检查）
try:
    import dingtalk_stream
    STREAM_AVAILABLE = True
except ImportError:
    dingtalk_stream = None
    STREAM_AVAILABLE = False
    _logger.warning("⚠️  dingtalk-stream 库未安装，Stream 功能不可用")


class DingTalkStreamBot(models.Model):
    """钉钉 Stream 机器人配置和消息接收"""
    _name = 'dingtalk.stream.bot'
    _description = '钉钉 Stream 机器人'
    _rec_name = 'name'
    _inherit = ['mail.thread', 'mail.activity.mixin']
    
    name = fields.Char(string="机器人名称", required=True, default="Stream 接收机器人")
    active = fields.Boolean(string="启用", default=True)
    
    # 配置
    config_id = fields.Many2one('dingtalk.config', string="钉钉配置", required=True,
                               default=lambda self: self.env['dingtalk.config'].search([('active', '=', True)], limit=1))
    
    # AI 配置
    enable_ai = fields.Boolean(string="启用 AI 助手", default=True,
                              help="使用 DeepSeek AI 回答 Odoo 相关问题")
    ai_api_key = fields.Char(string="DeepSeek API Key", groups="base.group_system",
                            default="sk-8aa0d25816694d568c5a7b0418903a4f",
                            help="DeepSeek API Key")
    ai_model = fields.Char(string="AI 模型", default="deepseek-chat",
                          help="DeepSeek 模型名称")
    
    # 运行状态
    is_running = fields.Boolean(string="正在运行", default=False, readonly=True,
                                help="Stream 客户端是否正在运行")
    last_start_time = fields.Datetime(string="最后启动时间", readonly=True)
    last_stop_time = fields.Datetime(string="最后停止时间", readonly=True)
    
    # 统计
    total_received = fields.Integer(string="接收消息数", default=0, readonly=True)
    total_replied = fields.Integer(string="回复消息数", default=0, readonly=True)
    
    def action_start_stream(self):
        """启动 Stream 客户端"""
        self.ensure_one()
        
        if self.is_running:
            raise ValidationError(_('Stream 客户端已在运行中'))
        
        try:
            # 启动 Stream 客户端（在后台线程中）
            self._start_stream_client()
            
            self.write({
                'is_running': True,
                'last_start_time': fields.Datetime.now(),
            })
            
            return {
                'type': 'ir.actions.client',
                'tag': 'display_notification',
                'params': {
                    'title': _('✅ Stream 客户端已启动'),
                    'message': _('钉钉机器人正在监听消息...'),
                    'type': 'success',
                    'sticky': False,
                }
            }
        except Exception as e:
            _logger.error(f"❌ 启动 Stream 客户端失败: {str(e)}")
            raise ValidationError(_('启动失败: %s') % str(e))
    
    def action_stop_stream(self):
        """停止 Stream 客户端"""
        self.ensure_one()
        
        try:
            self._stop_stream_client()
            
            self.write({
                'is_running': False,
                'last_stop_time': fields.Datetime.now(),
            })
            
            return {
                'type': 'ir.actions.client',
                'tag': 'display_notification',
                'params': {
                    'title': _('✅ Stream 客户端已停止'),
                    'message': _('钉钉机器人已停止监听'),
                    'type': 'info',
                    'sticky': False,
                }
            }
        except Exception as e:
            _logger.error(f"❌ 停止 Stream 客户端失败: {str(e)}")
            raise ValidationError(_('停止失败: %s') % str(e))
    
    def _start_stream_client(self):
        """启动 Stream 客户端（后台线程）"""
        global _stream_client, _stream_thread
        
        if _stream_client is not None:
            _logger.warning("Stream 客户端已在运行")
            return
        
        try:
            import dingtalk_stream
        except ImportError:
            raise ValidationError(
                _('未安装 dingtalk-stream 库！\n\n'
                  '请在服务器上运行：\n'
                  'pip install dingtalk-stream'))
        
        # 获取配置
        client_id = self.config_id.app_key
        client_secret = self.config_id.app_secret
        
        _logger.info("=" * 80)
        _logger.info("🤖 启动钉钉 Stream 客户端")
        _logger.info(f"   ClientID: {client_id}")
        _logger.info("=" * 80)
        
        # 创建 Stream 客户端
        credential = dingtalk_stream.Credential(client_id, client_secret)
        _stream_client = dingtalk_stream.DingTalkStreamClient(credential)
        
        # 注册机器人消息处理器（传递 AI 配置）
        handler = OdooStreamBotHandler(
            self.env, 
            self.id,
            enable_ai=self.enable_ai,
            ai_api_key=self.ai_api_key,
            ai_model=self.ai_model
        )
        _stream_client.register_callback_handler(
            dingtalk_stream.chatbot.ChatbotMessage.TOPIC, 
            handler
        )
        
        # 在后台线程中启动
        def run_stream():
            try:
                _logger.info("🚀 Stream 客户端开始运行...")
                _stream_client.start_forever()
            except Exception as e:
                _logger.error(f"❌ Stream 客户端异常: {str(e)}")
                import traceback
                _logger.error(traceback.format_exc())
        
        _stream_thread = threading.Thread(target=run_stream, daemon=True)
        _stream_thread.start()
        
        _logger.info("✅ Stream 客户端已在后台启动")
    
    def _stop_stream_client(self):
        """停止 Stream 客户端"""
        global _stream_client, _stream_thread
        
        if _stream_client is None:
            _logger.warning("Stream 客户端未运行")
            return
        
        try:
            _logger.info("🛑 正在停止 Stream 客户端...")
            # Stream 客户端会在线程退出时自动清理
            _stream_client = None
            _stream_thread = None
            _logger.info("✅ Stream 客户端已停止")
        except Exception as e:
            _logger.error(f"❌ 停止 Stream 客户端失败: {str(e)}")


class OdooStreamBotHandler(dingtalk_stream.ChatbotHandler if STREAM_AVAILABLE else object):
    """Odoo Stream 机器人消息处理器 - AI 驱动的 Odoo 助手"""
    
    def __init__(self, env, bot_id, enable_ai=True, ai_api_key=None, ai_model="deepseek-chat", logger=None):
        super().__init__()
        self.env = env
        self.bot_id = bot_id
        self.enable_ai = enable_ai
        self.ai_api_key = ai_api_key
        self.ai_model = ai_model
        if logger:
            self.logger = logger
        else:
            self.logger = logging.getLogger(__name__)
    
    async def process(self, callback: 'dingtalk_stream.CallbackMessage'):
        """处理收到的消息"""
        try:
            import dingtalk_stream
            
            # 解析消息
            incoming_message = dingtalk_stream.ChatbotMessage.from_dict(callback.data)
            
            sender_id = incoming_message.sender_id
            sender_nick = incoming_message.sender_nick
            message_text = incoming_message.text.content.strip()
            conversation_id = incoming_message.conversation_id
            
            self.logger.info("=" * 80)
            self.logger.info("📨 收到钉钉消息")
            self.logger.info(f"   发送人: {sender_nick} ({sender_id})")
            self.logger.info(f"   内容: {message_text}")
            self.logger.info(f"   会话ID: {conversation_id}")
            self.logger.info("=" * 80)
            
            # 保存消息到 Odoo（在新的数据库游标中）
            with self.env.registry.cursor() as new_cr:
                new_env = api.Environment(new_cr, self.env.uid, self.env.context)
                
                # 保存收到的消息
                new_env['dingtalk.received.message'].create({
                    'sender_id': sender_id,
                    'sender_nick': sender_nick,
                    'message_content': message_text,
                    'conversation_id': conversation_id,
                    'message_type': 'text',
                    'raw_data': str(callback.data),
                })
                new_cr.commit()
                
                # 更新统计
                bot = new_env['dingtalk.stream.bot'].browse(self.bot_id)
                bot.write({'total_received': bot.total_received + 1})
                new_cr.commit()
            
            # 处理消息并回复
            reply_text = self._process_message(message_text, sender_nick)
            
            # 回复消息
            self.reply_text(reply_text, incoming_message)
            
            # 更新回复统计
            with self.env.registry.cursor() as new_cr:
                new_env = api.Environment(new_cr, self.env.uid, self.env.context)
                bot = new_env['dingtalk.stream.bot'].browse(self.bot_id)
                bot.write({'total_replied': bot.total_replied + 1})
                new_cr.commit()
            
            self.logger.info(f"✅ 已回复: {reply_text}")
            
            return dingtalk_stream.AckMessage.STATUS_OK, 'OK'
            
        except Exception as e:
            self.logger.error(f"❌ 处理消息失败: {str(e)}")
            import traceback
            self.logger.error(traceback.format_exc())
            return dingtalk_stream.AckMessage.STATUS_SYSTEM_EXCEPTION, str(e)
    
    def _process_message(self, message_text, sender_nick):
        """处理消息逻辑 - AI 驱动的 Odoo 助手"""
        
        # 如果启用了 AI，优先使用 AI 回复
        if self.enable_ai and self.ai_api_key:
            ai_response = self._get_ai_response(message_text, sender_nick)
            if ai_response:
                return ai_response
        
        # 如果 AI 未启用或失败，使用关键词回复
        message_lower = message_text.lower()
        
        if '你好' in message_text or 'hello' in message_lower or 'hi' in message_lower:
            return f"你好，{sender_nick}！我是 Odoo AI 助手，由 DeepSeek 驱动。\n\n我可以帮你解答：\n- Odoo 使用问题\n- Odoo 开发问题\n- 系统功能说明\n- 业务流程指导\n\n直接问我任何 Odoo 相关问题吧！"
        
        elif '帮助' in message_text or 'help' in message_lower:
            return """🤖 Odoo AI 助手

我是由 DeepSeek AI 驱动的 Odoo 培训和指导老师！

✅ 我能做什么：
• 回答 Odoo 使用问题
• 解答 Odoo 开发问题
• 解释系统功能和配置
• 提供最佳实践建议
• 帮助排查问题

💬 使用方式：
直接向我提问即可，例如：
- "如何创建销售订单？"
- "Odoo 的 ORM 怎么用？"
- "如何自定义视图？"
- "计算字段怎么写？"

📚 我了解：
• Odoo 18 最新特性
• Python 开发
• XML 视图设计
• 业务流程配置
• 权限管理
• 报表开发

随时问我任何 Odoo 相关问题！"""
        
        # 简单计算（作为备用功能）
        elif any(op in message_text for op in ['+', '-', '*', '/', '(', ')']):
            try:
                result = eval(message_text, {"__builtins__": {}}, {})
                return f"💡 计算结果: {message_text} = {result}"
            except:
                pass
        
        # 默认回复
        return f"收到你的消息：{message_text}\n\n💡 提示：我现在是 AI 助手，可以回答 Odoo 相关问题。\n\n如果 AI 功能未启用，请联系管理员配置 DeepSeek API Key。"
    
    def _get_ai_response(self, message_text, sender_nick):
        """使用 DeepSeek AI 生成回复（支持函数调用）"""
        try:
            from openai import OpenAI
            import json
            
            # 创建 DeepSeek 客户端（兼容 OpenAI API）
            client = OpenAI(
                api_key=self.ai_api_key,
                base_url="https://api.deepseek.com"
            )
            
            # 构建系统提示词
            system_prompt = """你是一个专业的 Odoo ERP 系统培训和指导老师，同时可以直接操作 Odoo 宿舍管理系统。

你的能力：
1. 回答 Odoo 使用、开发、配置问题
2. 提供代码示例和最佳实践
3. 直接查询和创建宿舍管理数据（房间、学生等）

可用的工具函数：
- create_room: 创建宿舍房间
- query_rooms: 查询房间信息
- create_student: 创建学生记录
- query_students: 查询学生信息

当用户要求创建或查询数据时，使用相应的工具函数。

回答要求：
- 简洁明了（500字以内）
- 使用友好的语气
- 如果使用了工具函数，告诉用户操作结果

系统信息：
- Odoo 18.0
- 宿舍管理模块、钉钉集成模块"""
            
            # 定义可用的工具函数
            tools = [
                {
                    "type": "function",
                    "function": {
                        "name": "create_room",
                        "description": "在宿舍管理系统中创建新房间",
                        "parameters": {
                            "type": "object",
                            "properties": {
                                "hostel_name": {
                                    "type": "string",
                                    "description": "宿舍名称，例如：大学男生宿舍"
                                },
                                "room_no": {
                                    "type": "string",
                                    "description": "房间编号，例如：505"
                                },
                                "floor": {
                                    "type": "string",
                                    "description": "楼层，例如：5"
                                },
                                "rent_amount": {
                                    "type": "number",
                                    "description": "租金金额，例如：2000"
                                }
                            },
                            "required": ["hostel_name", "room_no"]
                        }
                    }
                },
                {
                    "type": "function",
                    "function": {
                        "name": "query_rooms",
                        "description": "查询宿舍房间信息",
                        "parameters": {
                            "type": "object",
                            "properties": {
                                "room_no": {
                                    "type": "string",
                                    "description": "房间编号（可选）"
                                },
                                "hostel_name": {
                                    "type": "string",
                                    "description": "宿舍名称（可选）"
                                },
                                "limit": {
                                    "type": "integer",
                                    "description": "返回结果数量限制，默认10",
                                    "default": 10
                                }
                            }
                        }
                    }
                },
                {
                    "type": "function",
                    "function": {
                        "name": "query_students",
                        "description": "查询学生信息",
                        "parameters": {
                            "type": "object",
                            "properties": {
                                "name": {
                                    "type": "string",
                                    "description": "学生姓名（可选）"
                                },
                                "room_no": {
                                    "type": "string",
                                    "description": "房间编号（可选）"
                                },
                                "limit": {
                                    "type": "integer",
                                    "description": "返回结果数量限制，默认10",
                                    "default": 10
                                }
                            }
                        }
                    }
                }
            ]
            
            self.logger.info(f"🤖 向 DeepSeek AI 发送请求（支持函数调用）...")
            self.logger.info(f"   用户: {sender_nick}")
            self.logger.info(f"   问题: {message_text}")
            
            # 第一次调用：让 AI 决定是否需要调用函数
            messages = [
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": message_text}
            ]
            
            response = client.chat.completions.create(
                model=self.ai_model,
                messages=messages,
                tools=tools,
                max_tokens=800,
                temperature=0.7,
            )
            
            response_message = response.choices[0].message
            tool_calls = response_message.tool_calls
            
            # 如果 AI 决定调用函数
            if tool_calls:
                self.logger.info(f"🔧 AI 决定调用 {len(tool_calls)} 个函数")
                
                # 将 AI 的响应添加到对话历史
                messages.append(response_message)
                
                # 执行所有函数调用
                for tool_call in tool_calls:
                    function_name = tool_call.function.name
                    function_args = json.loads(tool_call.function.arguments)
                    
                    self.logger.info(f"   调用函数: {function_name}")
                    self.logger.info(f"   参数: {function_args}")
                    
                    # 执行函数
                    function_result = self._execute_tool_function(function_name, function_args)
                    
                    self.logger.info(f"   结果: {function_result}")
                    
                    # 将函数结果添加到对话历史
                    messages.append({
                        "tool_call_id": tool_call.id,
                        "role": "tool",
                        "name": function_name,
                        "content": json.dumps(function_result, ensure_ascii=False)
                    })
                
                # 第二次调用：让 AI 根据函数结果生成最终回复
                self.logger.info(f"🤖 根据函数结果生成最终回复...")
                
                second_response = client.chat.completions.create(
                    model=self.ai_model,
                    messages=messages,
                    max_tokens=500,
                    temperature=0.7,
                )
                
                ai_reply = second_response.choices[0].message.content.strip()
            else:
                # AI 决定不调用函数，直接回答
                ai_reply = response_message.content.strip()
            
            self.logger.info(f"✅ DeepSeek AI 回复: {ai_reply[:100]}...")
            
            # 添加 AI 标记
            formatted_reply = f"🤖 Odoo AI 助手\n\n{ai_reply}\n\n---\n💡 我可以帮你操作数据，也可以回答问题！"
            
            return formatted_reply
            
        except Exception as e:
            self.logger.error(f"❌ AI 回复失败: {str(e)}")
            import traceback
            self.logger.error(traceback.format_exc())
            return None  # 返回 None 会使用默认关键词回复
    
    def _execute_tool_function(self, function_name, arguments):
        """执行工具函数"""
        try:
            if function_name == 'create_room':
                return self._tool_create_room(**arguments)
            elif function_name == 'query_rooms':
                return self._tool_query_rooms(**arguments)
            elif function_name == 'query_students':
                return self._tool_query_students(**arguments)
            else:
                return {"error": f"未知的函数: {function_name}"}
        except Exception as e:
            self.logger.error(f"❌ 执行函数 {function_name} 失败: {str(e)}")
            return {"error": str(e)}
    
    def _tool_create_room(self, hostel_name, room_no, floor=None, rent_amount=None):
        """工具函数：创建宿舍房间"""
        try:
            with self.env.registry.cursor() as new_cr:
                new_env = api.Environment(new_cr, self.env.uid, self.env.context)
                
                # 查找宿舍
                hostel = new_env['hostel.hostel'].search([
                    ('name', '=', hostel_name)
                ], limit=1)
                
                if not hostel:
                    # 如果宿舍不存在，自动创建（提供必填字段的默认值）
                    hostel_code = hostel_name[:4].upper() if len(hostel_name) >= 4 else hostel_name.upper()
                    hostel = new_env['hostel.hostel'].create({
                        'name': hostel_name,
                        'hostel_code': hostel_code,
                        'phone': '000-0000-0000',  # 必填：电话（默认值）
                        'mobile': '000-0000-0000', # 必填：手机（默认值）
                        'type': 'common',          # 必填：类型（默认为通用）
                    })
                    self.logger.info(f"  ✅ 自动创建新宿舍: {hostel_name}")
                    self.logger.info(f"     （电话和手机为默认值，可在系统中修改）")
                
                # 检查房间是否已存在
                existing_room = new_env['hostel.room'].search([
                    ('hostel_id', '=', hostel.id),
                    ('room_no', '=', room_no)
                ], limit=1)
                
                if existing_room:
                    self.logger.warning(f"  ⚠️  房间已存在: {room_no}")
                    return {
                        "success": False,
                        "error": f"房间 {room_no} 在 {hostel_name} 中已存在",
                        "existing_room": {
                            "room_no": existing_room.room_no,
                            "floor": existing_room.floor_no or "未设置",
                            "rent_amount": existing_room.rent_amount or 0,
                            "state": existing_room.state,
                        }
                    }
                
                # 创建房间
                room_vals = {
                    'name': f'Room {room_no}',  # 必填：房间名称
                    'hostel_id': hostel.id,
                    'room_no': room_no,         # 必填：房间编号
                }
                
                if floor:
                    room_vals['floor_no'] = int(floor)  # 注意：字段名是 floor_no，不是 floor
                if rent_amount:
                    room_vals['rent_amount'] = float(rent_amount)
                
                room = new_env['hostel.room'].create(room_vals)
                new_cr.commit()
                
                self.logger.info(f"  ✅ 创建房间成功: {room_no}")
                
                return {
                    "success": True,
                    "room_id": room.id,
                    "room_name": room.name,
                    "room_no": room.room_no,
                    "hostel_name": hostel.name,
                    "hostel_code": hostel.hostel_code,
                    "floor": room.floor_no or "未设置",
                    "rent_amount": room.rent_amount or 0,
                    "state": room.state,
                    "message": f"成功创建房间 {room_no}（{hostel_name}）"
                }
        except Exception as e:
            self.logger.error(f"  ❌ 创建房间失败: {str(e)}")
            import traceback
            self.logger.error(traceback.format_exc())
            return {"success": False, "error": str(e)}
    
    def _tool_query_rooms(self, room_no=None, hostel_name=None, limit=10):
        """工具函数：查询房间信息"""
        try:
            with self.env.registry.cursor() as new_cr:
                new_env = api.Environment(new_cr, self.env.uid, self.env.context)
                
                domain = []
                if room_no:
                    domain.append(('room_no', 'ilike', room_no))
                if hostel_name:
                    domain.append(('hostel_id.name', 'ilike', hostel_name))
                
                rooms = new_env['hostel.room'].search(domain, limit=limit)
                
                result = {
                    "success": True,
                    "count": len(rooms),
                    "rooms": []
                }
                
                for room in rooms:
                    result["rooms"].append({
                        "room_name": room.name,
                        "room_no": room.room_no,
                        "hostel_name": room.hostel_id.name if room.hostel_id else "未分配",
                        "floor": room.floor_no or "未设置",
                        "rent_amount": room.rent_amount or 0,
                        "state": room.state,
                        "student_count": len(room.student_ids),
                        "availability": room.availability,
                    })
                
                self.logger.info(f"  ✅ 查询到 {len(rooms)} 个房间")
                return result
                
        except Exception as e:
            self.logger.error(f"  ❌ 查询房间失败: {str(e)}")
            return {"success": False, "error": str(e)}
    
    def _tool_query_students(self, name=None, room_no=None, limit=10):
        """工具函数：查询学生信息"""
        try:
            with self.env.registry.cursor() as new_cr:
                new_env = api.Environment(new_cr, self.env.uid, self.env.context)
                
                domain = []
                if name:
                    domain.append(('name', 'ilike', name))
                if room_no:
                    domain.append(('room_id.room_no', 'ilike', room_no))
                
                students = new_env['hostel.student'].search(domain, limit=limit)
                
                result = {
                    "success": True,
                    "count": len(students),
                    "students": []
                }
                
                for student in students:
                    result["students"].append({
                        "name": student.name,
                        "gender": student.gender,
                        "class_id": student.class_id,
                        "room_no": student.room_id.room_no if student.room_id else "未分配",
                        "hostel_name": student.hostel_id.name if student.hostel_id else "未分配",
                        "status": student.status,
                    })
                
                self.logger.info(f"  ✅ 查询到 {len(students)} 个学生")
                return result
                
        except Exception as e:
            self.logger.error(f"  ❌ 查询学生失败: {str(e)}")
            return {"success": False, "error": str(e)}


class DingTalkReceivedMessage(models.Model):
    """钉钉收到的消息记录"""
    _name = 'dingtalk.received.message'
    _description = '钉钉收到的消息'
    _rec_name = 'sender_nick'
    _order = 'create_date desc'
    _inherit = ['mail.thread', 'mail.activity.mixin']
    
    sender_id = fields.Char(string="发送人ID", required=True, index=True)
    sender_nick = fields.Char(string="发送人昵称", required=True)
    message_content = fields.Text(string="消息内容", required=True, tracking=True)
    conversation_id = fields.Char(string="会话ID", index=True)
    message_type = fields.Selection([
        ('text', '文本'),
        ('image', '图片'),
        ('file', '文件'),
        ('voice', '语音'),
        ('other', '其他'),
    ], string="消息类型", default='text')
    
    # 原始数据
    raw_data = fields.Text(string="原始数据", help="钉钉返回的原始 JSON 数据")
    
    # 处理状态
    is_processed = fields.Boolean(string="已处理", default=False)
    reply_content = fields.Text(string="回复内容", tracking=True)
    replied_time = fields.Datetime(string="回复时间")
    
    # 关联
    employee_id = fields.Many2one('dingtalk.employee', string="关联员工",
                                 compute='_compute_employee_id', store=True)
    user_id = fields.Many2one('res.users', string="关联用户",
                             compute='_compute_user_id', store=True)
    
    @api.depends('sender_id')
    def _compute_employee_id(self):
        """自动关联钉钉员工"""
        for record in self:
            if record.sender_id:
                employee = self.env['dingtalk.employee'].search([
                    ('userid', '=', record.sender_id)
                ], limit=1)
                record.employee_id = employee.id if employee else False
            else:
                record.employee_id = False
    
    @api.depends('employee_id')
    def _compute_user_id(self):
        """自动关联系统用户"""
        for record in self:
            if record.employee_id and record.employee_id.user_id:
                record.user_id = record.employee_id.user_id.id
            else:
                record.user_id = False

